import formencode
from sqlalchemy import orm
from sqlalchemy.ext.associationproxy import association_proxy

from cibynet.lib import network
from cibynet.model import tables as t
from cibynet.model.m_machines_ips import MachineIp
from cibynet.model import utils as m_utils


class Machine(object):
  """Machine/computer belonging to one student.
  """
    
  ips = association_proxy('ipassociations', 'ip', 
                            creator=lambda i, **kw:MachineIp(ip=i, **kw))
  
  def __init__(self, user, hostname, macaddress, active=True):
    self.user = user
    self.hostname = hostname
    self.macaddress = macaddress
    self.active = active
    self.last_connection = None

  def _get_ipassoc(self):
    """Returns the last (chronogical) IP association of the room.
    """
    return orm.object_session(self).query(MachineIp).\
           filter_by(machine_id=self.id).\
           order_by(t.machines_ips.c.id.desc()).limit(1).first()
    
  def _get_ip(self):
    """Returns the last ip of the machine if the machine has one.
       If the machine has no ip assigned, returns None.
    """
    assoc = self._get_ipassoc()
    if assoc and not assoc.to_date:
      return assoc.ip
    return None
  ip = property(_get_ip)
  
  def ping(self):
    """Ping the machine and return True if the machine answers, False otherwise. 
    """
    if not self.ip:
      return False
    return network.ping(self.ip.address)
  
  def __repr__(self):
    return "<Machine %s, %s>" % (self.hostname, self.macaddress)
  
  
  
class HostnameNewValidator(formencode.validators.PlainText):
  """Validate a hostname for a new machine.
  This hostname must not be attributed to any machine.
  TODO: only allow string, digits and "_". No dots or others.
  """
  def validate_other(self, value, c):
    """
    """
    value = value.lower()
    ids = m_utils.GetAllIdsObject(Machine, hostname=value)
    if ids:
      raise formencode.validators.Invalid('This hostname is already being used',
                                           value, c)
    return value

hostname_new_validator = HostnameNewValidator(strip=True, not_empty=True)
macaddress_validator = formencode.validators.MACAddress(not_empty=True)


class MachineNewValidator(formencode.Schema):
  """
  Only check for the hostname and the macaddress.
  Does not check the presence of any user id or what's ever.
  """
  allow_extra_fields = True
  filter_extra_fields = False
  hostname = hostname_new_validator
  macaddress = macaddress_validator

